#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>       
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>


static long U[256], V[256], Y1[256], Y2[256]; 
#ifndef MAX  
#define MAX(a, b) ((a) > (b) ? (a) : (b))  
#endif  
#ifndef MIN  
#define MIN(a, b) ((a) < (b) ? (a) : (b))  
#endif  

long seek = 0;

#define FMT_YUYV 0
#define FMT_YVYU 1
#define FMT_UYVY 2
#define FMT_VYUY 3
#define FMT_NV12 4
#define FMT_NV21 5
unsigned char src_data[4096*4096*4];
unsigned char des_data[4096*4096*4];
GdkPixbuf *pixbuf;

static long int crv_tab[256];     
static long int cbu_tab[256];     
static long int cgu_tab[256];     
static long int cgv_tab[256];     
static long int tab_76309[256];   
static unsigned char clp[1024];   //for clip in CCIR601   



/*转换查询表的生成函数*/

void init_yuv420p_table()   
{     
    long int crv,cbu,cgu,cgv;     
    int i,ind;        
    static int init = 0;  
  
    if (init == 1) return;  
  
    crv = 104597; cbu = 132201;  /* fra matrise i global.h */     
    cgu = 25675;  cgv = 53279;     
     
    for (i = 0; i < 256; i++)      
    {     
        crv_tab[i] = (i-128) * crv;     
        cbu_tab[i] = (i-128) * cbu;     
        cgu_tab[i] = (i-128) * cgu;     
        cgv_tab[i] = (i-128) * cgv;     
        tab_76309[i] = 76309*(i-16);     
    }     
     
    for (i = 0; i < 384; i++)     
        clp[i] = 0;     
    ind = 384;     
    for (i = 0;i < 256; i++)     
        clp[ind++] = i;     
    ind = 640;     
    for (i = 0;i < 384; i++)     
        clp[ind++] = 255;  
  
    init = 1;  
}  

/*
 * 函数名称 : init_yuv422p_table
 * 函数介绍 : 将FMT_YUYV,FMT_YVYU,FMT_UYVY,FMT_VYUY转换成rgb24格式
 * 参数介绍 : 生成查询表格
 */  
void init_yuv422p_table(void)  
{  
    int i;  
    static int init = 0;  
    if (init == 1) return;  
    // Initialize table  
    for (i = 0; i < 256; i++)  
    {   
        V[i]  = 15938 * i - 2221300;  
        U[i]  = 20238 * i - 2771300;  
        Y1[i] = 11644 * i;  
        Y2[i] = 19837 * i - 311710;  
    }  
  
    init = 1;  
} 


/*
 * 函数名称 : yuv420sp_to_rgb24
 * 函数介绍 : 将FMT_NV12,FMT_NV21转换成rgb24格式
 * 参数介绍 : 生成查询表格
 */
void yuv420sp_to_rgb24(int type, unsigned char* yuvbuffer,unsigned char* rgbbuffer, int width,int height)     
{  
    int y1, y2, u, v;      
    unsigned char *py1, *py2;     
    int i, j, c1, c2, c3, c4;     
    unsigned char *d1, *d2;     
    unsigned char *src_u;  
    static int init_yuv420p = 0;  
  
    src_u = yuvbuffer + width * height;   // u  
  
    py1 = yuvbuffer;   // y  
    py2 = py1 + width;     
    d1 = rgbbuffer;     
    d2 = d1 + 3 * width;     
  
    init_yuv420p_table();  
  
    for (j = 0; j < height; j += 2)      
    {      
        for (i = 0; i < width; i += 2)      
        {  
            if (type ==  FMT_NV12)  
            {  
                u = *src_u++;     
                v = *src_u++;      // v紧跟u，在u的下一个位置  
            }  
            if (type == FMT_NV21)  
            {  
                v = *src_u++;     
                u = *src_u++;      // u紧跟v，在v的下一个位置  
            }  
  
            c1 = crv_tab[v];     
            c2 = cgu_tab[u];     
            c3 = cgv_tab[v];     
            c4 = cbu_tab[u];     
  
            //up-left     
            y1 = tab_76309[*py1++];      
            *d1++ = clp[384+((y1 + c1)>>16)];       
            *d1++ = clp[384+((y1 - c2 - c3)>>16)];     
            *d1++ = clp[384+((y1 + c4)>>16)];     
  
            //down-left     
            y2 = tab_76309[*py2++];     
            *d2++ = clp[384+((y2 + c1)>>16)];       
            *d2++ = clp[384+((y2 - c2 - c3)>>16)];     
            *d2++ = clp[384+((y2 + c4)>>16)];     
  
            //up-right     
            y1 = tab_76309[*py1++];     
            *d1++ = clp[384+((y1 + c1)>>16)];       
            *d1++ = clp[384+((y1 - c2 - c3)>>16)];     
            *d1++ = clp[384+((y1 + c4)>>16)];     
  
            //down-right     
            y2 = tab_76309[*py2++];     
            *d2++ = clp[384+((y2 + c1)>>16)];       
            *d2++ = clp[384+((y2 - c2 - c3)>>16)];     
            *d2++ = clp[384+((y2 + c4)>>16)];     
        }  
        d1  += 3*width;  
        d2  += 3*width;  
        py1 += width;  
        py2 += width;  
    }  
}  

/*
 * 函数名称 : yuv422packed_to_rgb24
 * 函数介绍 : 将FMT_YUYV,FMT_YVYU,FMT_UYVY,FMT_VYUY转换成rgb24格式
 * 参数介绍 : typr : YUV422的格式
 *          yuv422p : YUV422的数据字节
 *          rgb : 生成的RGB数据字节
 *          width,height : 图片的宽高
 */
void yuv422packed_to_rgb24(int type, unsigned char* yuv422p, unsigned char* rgb, int width, int height)  
{  
    int y, cb, cr;  
    int r, g, b;  
    int i = 0;  
    unsigned char* p;  
    unsigned char* p_rgb;  
  
    p = yuv422p;  
  
    p_rgb = rgb;  
  
    init_yuv422p_table();  
  
    for (i = 0; i < width * height / 2; i++)  
    {  
        switch(type)  
        {  
        case FMT_YUYV:  
            y  = p[0];  
            cb = p[1];  
            cr = p[3];  
            break;  
        case FMT_YVYU:  
            y  = p[0];  
            cr = p[1];  
            cb = p[3];  
            break;  
        case FMT_UYVY:  
            cb = p[0];  
            y  = p[1];  
            cr = p[2];  
            break;  
        case FMT_VYUY:  
            cr = p[0];  
            y  = p[1];  
            cb = p[2];  
            break;  
        default:  
            break;  
        }  
  
        r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000));   //R value  
        b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000));   //B value  
        g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value  
  
        // 此处可调整RGB排序，BMP图片排序为BGR  
        // 默认排序为：RGB  
        p_rgb[0] = r;  
        p_rgb[1] = g;  
        p_rgb[2] = b;  
  
        switch(type)  
        {  
        case FMT_YUYV:  
        case FMT_YVYU:  
            y = p[2];  
            break;  
        case FMT_UYVY:  
        case FMT_VYUY:  
            y = p[3];  
            break;  
        default:  
            break;  
        }  
  
        r = MAX (0, MIN (255, (V[cr] + Y1[y])/10000));   //R value  
        b = MAX (0, MIN (255, (U[cb] + Y1[y])/10000));   //B value  
        g = MAX (0, MIN (255, (Y2[y] - 5094*(r) - 1942*(b))/10000)); //G value  
  
        p_rgb[3] = r;  
        p_rgb[4] = g;  
        p_rgb[5] = b;  
  
        p += 4;  
        p_rgb += 6;  
    }  
}  


void my_draw_able_expose (GtkWidget *w, GdkEventExpose *e, gpointer data)
{
    gdk_draw_pixbuf (GTK_WIDGET (w)->window, NULL, pixbuf,0,0,0,0,1280,720, GDK_RGB_DITHER_NORMAL, 0, 0);
}


int loadFromFile(int fd, long frame, int width, int height, int fmt)
{
    int frameSize = 0;
    switch(fmt)
    {
        case FMT_YUYV:
        case FMT_YVYU:
        case FMT_UYVY:
        case FMT_VYUY:
            //每帧数据的大小
            frameSize = width*height*2;
        break;
        case FMT_NV12:
        case FMT_NV21:
            //每帧数据的大小
            frameSize = width*height*3/2;
        break;
    }
    seek = frameSize*frame;

    //移动到指定位置
    lseek(fd, seek, SEEK_SET);
    int ret;
    if ( (ret = read(fd, src_data, frameSize)) == -1) {
        perror("read:");
        return -1;
    }
    else
    {
        printf("seek=%ld   ret=%d\n", seek, ret);
    }

    switch(fmt)
    {
        case FMT_YUYV:
        case FMT_YVYU:
        case FMT_UYVY:
        case FMT_VYUY:
            /* 按照制定的格式进行数据的装换 */
            yuv422packed_to_rgb24(fmt,src_data, des_data, width, height);
        break;
        case FMT_NV12:
        case FMT_NV21:
            /* 按照制定的格式进行数据的装换 */
            yuv420sp_to_rgb24(fmt,src_data, des_data, width, height);
        break;
    }

    /* 从字节数据中创建pixbuf */
    pixbuf = gdk_pixbuf_new_from_data ((guchar* )des_data, GDK_COLORSPACE_RGB, 
           FALSE, 8, width, height, width*3, 0, 0);
    return 0;

}

int main (int argc, char *argv[])
{
        GtkWidget *window;
        GtkWidget *draw_able;
        int i,j,pos =0;
        int fd;
        int ret;
        int fmt;
        int width;
        int height;
        int frame;

        gtk_init (&argc, &argv);



        if( argc < 6 )
        {
            printf("使用方法 : ./program FileName FMT Width Height WhichFrame\n");
            printf("FMT_YUYV 0\n");
            printf("FMT_YVYU 1\n");
            printf("FMT_UYVY 2\n");
            printf("FMT_VYUY 3\n");
            printf("FMT_NV12 4\n");
            printf("FMT_NV21 5\n");
            return 0;
        }

        fd = open(argv[1], O_RDWR,0777);
        if (fd <= 0)
        {
            perror("open:");
            return 0;
        }
        else
        {
            printf("文件 %s 的ID : %d\n", argv[1], fd);
        }

        fmt = atoi(argv[2]);
        width = atoi(argv[3]);
        height = atoi(argv[4]);
	    frame = atoi(argv[5]);
        

        /* 从文件中指定位置加载数据 */
        if ( loadFromFile(fd, frame, width, height, fmt) == -1)
        {
            perror("读取数据失败:");
            return -1;
        }

        window = gtk_window_new( GTK_WINDOW_TOPLEVEL);
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);  

        gtk_signal_connect (GTK_OBJECT (window), "delete_event",
                         GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
        draw_able = gtk_drawing_area_new ();
        gtk_widget_set_size_request (draw_able, 1280, 720);
        gtk_container_add (GTK_CONTAINER (window), draw_able);

        /* 设置刷新函数 */
        g_signal_connect (G_OBJECT (draw_able), "expose_event",
                             GTK_SIGNAL_FUNC(my_draw_able_expose),
                              NULL);


        gtk_widget_realize(draw_able);
        gtk_widget_show_all(window);
        gtk_main();
        close(fd);

     return 0;
}
